﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http.Headers;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using NPOI.HPSF;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Security;
using Senparc.Weixin.Work.AdvancedAPIs.OaDataOpen;
using SHZY.Business.Entitys;
using SHZY.Business.Entitys.OA;
using SHZY.Business.Interfaces;
using SHZY.Business.Interfaces.VideoRecording;
using SHZY.Common.Core.Manager;
using SHZY.Common.Core.Security;
using SHZY.Common.Enum;
using SHZY.Common.Security;
using SHZY.DependencyInjection;
using SHZY.DynamicApiController;
using SHZY.FriendlyException;
using SHZY.Systems.Interfaces.System;
using SHZY.WorkFlow.Interfaces.Manager;
using SHZY.WorkFlow.Interfaces.Repository;
using SqlSugar;
using Yitter.IdGenerator;

namespace SHZY.Business.OA
{
    /// <summary>
    /// 业务实现：OA接口实现.
    /// </summary>
    [ApiDescriptionSettings(Tag = "Business", Name = "QMSOA", Order = 200)]
    [Route("api/Business/[controller]")]
    public class QmsOAService : IQmsOAService, IDynamicApiController, ITransient
    {
        /// <summary>
        /// 服务基础仓储.
        /// </summary>
        private readonly ISqlSugarRepository<QmsBaseOASettingEntity> _repository;

        /// <summary>
        /// 数据接口服务.
        /// </summary>
        private readonly IDataInterfaceService _dataInterfaceService;

        /// <summary>
        /// 用户管理.
        /// </summary>
        private readonly IUserManager _userManager;

        private readonly ITenant _tenant;

        private readonly IFlowTaskRepository _flowTaskRepository;

        private readonly IFlowTaskManager _flowTaskManager;

        private readonly string _appid = string.Empty;
        private readonly string _ip = string.Empty;
        private readonly string _cpk = string.Empty;
        private readonly int _time = 1800; // 单位： 秒
        private readonly IHttpClientFactory _httpClientFactory;
        private readonly IConfiguration _configuration;

        /// <summary>
        /// 初始化一个<see cref="QmsOAService"/>类型的新实例.
        /// </summary>
        public QmsOAService(
            ISqlSugarRepository<QmsBaseOASettingEntity> qmsBaseOASettingRepository,
            IDataInterfaceService dataInterfaceService,
            ISqlSugarClient context,
            IUserManager userManager,
            IFlowTaskRepository flowTaskRepository,
            IFlowTaskManager flowTaskManager,
            IHttpClientFactory httpClientFactory,
            IConfiguration configuration)
        {
            _repository = qmsBaseOASettingRepository;
            _dataInterfaceService = dataInterfaceService;
            _userManager = userManager;
            _tenant = context.AsTenant();
            _flowTaskRepository = flowTaskRepository;
            _flowTaskManager = flowTaskManager;
            _httpClientFactory = httpClientFactory;
            _configuration = configuration;
            _appid = configuration["OA:appid"];
            _ip = configuration["OA:ip"];
            _cpk = configuration["OA:cpk"];
            _time = Convert.ToInt32(configuration["OA:time"]);
        }
        #region 获取spk

        /// <summary>
        /// 获取spk.
        /// </summary>
        /// <returns></returns>
        [HttpPost("GetSPKAsync")]
        private async Task<Result> GetSPKAsync()
        {
            var path = "/api/ec/dev/auth/regist";
            Dictionary<string, string> headers = new Dictionary<string, string>
            {
                { "appid", _appid },
                { "cpk", RsaEncrypt("123", _cpk) }
            };

            var resultMsg = await PostAsync(_ip + path, string.Empty, string.Empty, headers);
            var result = JsonConvert.DeserializeObject<Result>(resultMsg);
            if (result != null && result.status)
            {
                await _repository.DeleteAsync(d => d.Code == "spk" || d.Code == "secret");
                QmsBaseOASettingEntity spkInDto = new QmsBaseOASettingEntity()
                {
                    Id = SnowflakeIdHelper.NextId(),
                    Code = "spk",
                    Value = result.spk,
                    CreateTime = DateTime.Now
                };

                await _repository.InsertAsync(spkInDto);

                QmsBaseOASettingEntity secretInDto = new QmsBaseOASettingEntity()
                {
                    Id = SnowflakeIdHelper.NextId(),
                    Code = "secret",
                    Value = result.secret,
                    CreateTime = DateTime.Now
                };
                await _repository.InsertAsync(secretInDto);
            }

            return result;
        }
        #endregion

        #region 获取token

        /// <summary>
        /// 获取token
        /// </summary>
        /// <returns></returns>
        public async Task<string> GetTokenAsync()
        {
            var path = "/api/ec/dev/auth/applytoken";
            var spkValue = _repository.FirstOrDefault(d => d.Code == "spk")?.Value;
            var secretValue = _repository.FirstOrDefault(d => d.Code == "secret")?.Value;
            if (string.IsNullOrWhiteSpace(spkValue) || string.IsNullOrWhiteSpace(secretValue))
            {
                var spkResult = await GetSPKAsync();
                spkValue = spkResult.spk;
                secretValue = spkResult.secret;
            }
            var secret = RsaEncrypt(secretValue, spkValue);
            Dictionary<string, string> headers = new Dictionary<string, string>();
            headers.Add("appid", _appid);
            headers.Add("time", _time.ToString());
            headers.Add("secret", secret);

            var resultMsg = await PostAsync(_ip + path, string.Empty, string.Empty, headers);
            var result = JsonConvert.DeserializeObject<Result>(resultMsg);

            return await Task.FromResult(result.token);
        }
        #endregion


        #region 调用泛微接口发送消息

        [HttpPost("SendMessageAsync")]
        public async Task<Result> SendMessageAsync(Content content)
        {
            var path = _configuration["OA:apiurl"];
            RequestDto dto = new RequestDto();
            if (content.type == "Complaint")// 质量申诉单
            {
                dto.workflowId = _configuration["OA:ComplaintId"];
            }
            else if (content.type == "Processing")// 纠正和预防措施处理单
            {
                dto.workflowId = _configuration["OA:ProcessingId"];
            }
            else
            {
                throw Oops.Oh("类型错误,请检查!");
            }

            var spkValue = _repository.FirstOrDefault(d => d.Code == "spk")?.Value;

            var token = await GetTokenAsync();
            Dictionary<string, string> headers = new Dictionary<string, string>
            {
                { "token", token },
                { "appid", _appid },
                { "userid", RsaEncrypt("123", spkValue)}, // 对用户信息进行加密传输,暂仅支持传输OA用户ID 通过第一步注册许可时返回spk公钥对userid进行加密生成的密文
                { "Content-Type", "application/x-www-form-urlencoded;charset=utf-8" },  // POST请求必须设置Context-Type为”application/x-www-form-urlencoded; charset=utf-8”
                { "skipsession", "1" } // 是否跳过session拦截(用于白名单接口)，1代表是，0代表否（缺省）
            };
            dto.requestName = content.title;

            List<mainData> mainDatalist = new List<mainData>();
            mainData _mainData = new mainData();
            _mainData.fieldName = "sm";
            _mainData.fieldValue = content.context;

            mainData _mainData1 = new mainData();
            _mainData1.fieldName = "sqrgh";
            _mainData1.fieldValue = content.sqrgh;

            mainData _mainData2 = new mainData();
            _mainData2.fieldName = "pbbqrrgh";
            _mainData2.fieldValue = content.pbbqrrgh;

            mainData _mainData3 = new mainData();
            _mainData3.fieldName = "dh";
            _mainData3.fieldValue = content.orderNumber;

            mainData _mainData4 = new mainData();
            _mainData4.fieldName = "scfj";
            _mainData4.fieldValue = new
            {
                filePath = content.attachmentsPath,
                fileName = content.attachments
            };
            mainDatalist.Add(_mainData);
            mainDatalist.Add(_mainData1);
            mainDatalist.Add(_mainData4);
            dto.mainData = mainDatalist;

            var resultMsg = await PostAsync(_ip + path, JsonConvert.SerializeObject(dto), string.Empty, headers);

            //var data = $"code={content.code}&userIdList={content.userIdList}&creater={content.creater}&title={content.title}&context={content.context}";
            //var resultMsg = await Post3Async(_ip + path, data, headers);

            var result = JsonConvert.DeserializeObject<Result>(resultMsg);
            return result;
        }
        #endregion

        #region http post请求

        /// <summary>
        /// http post请求.
        /// </summary>
        /// <param name="requestUri">地址</param>
        /// <param name="parameter">入参</param>
        /// <param name="token"></param>
        /// <param name="headers">头信息</param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        private async Task<string> PostAsync(string requestUri, string parameter, string token, Dictionary<string, string> headers)
        {
            try
            {
                var client = _httpClientFactory.CreateClient();
                var content = new StringContent(parameter, Encoding.UTF8, "application/json");
                // 添加token到请求头中
                if (token != null)
                {
                    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
                }
                foreach (var header in headers)
                {
                    client.DefaultRequestHeaders.Add(header.Key, header.Value);
                }
                var response = await client.PostAsync(requestUri, content);
                string statusCode = ((int)response.StatusCode).ToString();
                response.EnsureSuccessStatusCode();
                string resultMsg = await response.Content.ReadAsStringAsync();
                // _logger.LogWarning($"返回结果：{resultMsg},入参：{parameter}");
                return resultMsg;
                //result = JsonConvert.DeserializeObject<Result>(resultMsg);
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message, ex);
            }
        }

        private async Task<string> Post2Async(string requestUri, Dictionary<string, string> parameter, string token, Dictionary<string, string> headers)
        {
            try
            {
                var client = _httpClientFactory.CreateClient();
                var content = new FormUrlEncodedContent(parameter);
                // 添加token到请求头中
                if (token != null)
                {
                    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
                }
                foreach (var header in headers)
                {
                    client.DefaultRequestHeaders.Add(header.Key, header.Value);
                }
                var response = await client.PostAsync(requestUri, content);
                string statusCode = ((int)response.StatusCode).ToString();
                response.EnsureSuccessStatusCode();
                string resultMsg = await response.Content.ReadAsStringAsync();
                // _logger.LogWarning($"返回结果：{resultMsg},入参：{parameter.ToJsonString()}");
                return resultMsg;
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message, ex);
            }
        }

        private async Task<string> Post3Async(string url, string parameter, Dictionary<string, string> headers)
        {
            using (var client = new HttpClient())
            {
                //var data = new StringContent("param1=value1&param2=value2", Encoding.UTF8, "application/x-www-form-urlencoded");
                var data = new StringContent(parameter, Encoding.UTF8, "application/x-www-form-urlencoded");
                //_logger.LogWarning($"data:{data.ToJsonString()}；parameter：{parameter}");
                // 添加header参数
                //client.DefaultRequestHeaders.Add("Authorization", "Bearer your_token_here");
                foreach (var header in headers)
                {
                    client.DefaultRequestHeaders.Add(header.Key, header.Value);
                }
                //_logger.LogWarning($"header:{client.DefaultRequestHeaders.ToJsonString()}");

                try
                {
                    var response = await client.PostAsync(url, data);
                    response.EnsureSuccessStatusCode();

                    var responseBody = await response.Content.ReadAsStringAsync();
                    return responseBody;
                }
                catch (HttpRequestException e)
                {
                    throw new Exception(e.Message);
                }
            }
        }
        #endregion

        #region RSA加密

        /// <summary>
        /// RSA加密.
        /// </summary>
        /// <param name="content">需加密文本</param>
        /// <param name="xmlpublickey">公钥</param>
        /// <returns></returns>
        private string RsaEncrypt(string content, string xmlpublickey)
        {
            string encryptedcontent = string.Empty;
            using (RSACryptoServiceProvider rSACryptoServiceProvider = new RSACryptoServiceProvider())
            {
                rSACryptoServiceProvider.FromXmlString(RSAPublicKeyBase64ToXml(xmlpublickey));
                byte[] encrypteddata = rSACryptoServiceProvider.Encrypt(Encoding.Default.GetBytes(content), false);
                encryptedcontent = Convert.ToBase64String(encrypteddata);
            }
            return encryptedcontent;
        }

        /// <summary>
        /// Base64 编码字符串转 XML 字符串（公钥）.
        /// </summary>
        /// <param name="publicKey"></param>
        /// <returns></returns>
        private static string RSAPublicKeyBase64ToXml(string publicKey)
        {
            RsaKeyParameters publicKeyParam = (RsaKeyParameters)PublicKeyFactory.CreateKey(Convert.FromBase64String(publicKey));
            return string.Format("<RSAKeyValue><Modulus>{0}</Modulus><Exponent>{1}</Exponent></RSAKeyValue>",
                                 Convert.ToBase64String(publicKeyParam.Modulus.ToByteArrayUnsigned()),
                                 Convert.ToBase64String(publicKeyParam.Exponent.ToByteArrayUnsigned()));
        }
        #endregion
    }
}
